#include "stm32f10x.h"
void RCC_Configuration(void);
void GPIO_Configuration(void);

TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;

u16 Channel1Pulse = 0;
u16 Channel2Pulse = 0;
u16 Channel3Pulse = 0;
u16 Channel4Pulse = 0;

u16 TimerPeriod = 0;

int main() {
    RCC_Configuration();
    GPIO_Configuration();

    TimerPeriod = (SystemCoreClock / 17570) - 1;

    Channel1Pulse = (u16)(((u32)5 * (TimerPeriod - 1)) / 10); // 50% channel 1 and 1N
    Channel2Pulse = (u16)(((u32)375 * (TimerPeriod - 1)) / 1000); // 37.5% channel 2 and 2N
    Channel3Pulse = (u16)(((u32)25 * (TimerPeriod - 1)) / 100); // 25% channel 3 and 3N
    Channel4Pulse = (u16)(((u32)125 * (TimerPeriod - 1)) / 1000); // 12.5% channel 4

    TIM_TimeBaseInitStructure.TIM_Prescaler = 0;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_Period = TimerPeriod;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStructure);

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
    TIM_OCInitStructure.TIM_Pulse = Channel1Pulse;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;

    TIM_OC1Init(TIM1, &TIM_OCInitStructure); 

    TIM_OCInitStructure.TIM_Pulse = Channel2Pulse;
    TIM_OC2Init(TIM1, &TIM_OCInitStructure);

    TIM_OCInitStructure.TIM_Pulse = Channel3Pulse;
    TIM_OC3Init(TIM1, &TIM_OCInitStructure);

    TIM_OCInitStructure.TIM_Pulse = Channel4Pulse;
    TIM_OC4Init(TIM1, &TIM_OCInitStructure);

    TIM_Cmd(TIM1, ENABLE);

    TIM_CtrlPWMOutputs(TIM1, ENABLE);
    
    while (1)
        ;
}

void RCC_Configuration() {
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

    RCC_APB2PeriphClockCmd(
        RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,
        ENABLE);
}

void GPIO_Configuration() {
    GPIO_InitTypeDef GPIO_InitStructure;

    // GPIOA Configration: Channel 1, 2 and 3 4
    GPIO_InitStructure.GPIO_Pin =
        GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // GPIOB Configration: Channel 1N 2N and 3N
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}
